package cachex

import (
	"gitee.com/zhongguo168a/gocodes/datax/schemax"
	"strings"
)

func (s *Object) RefGet(field string) (val interface{}) {
	s.mutex.RLock()
	val, _ = s.refGet(field)
	s.mutex.RUnlock()
	return
}

func (s *Object) RefAnyType() string {
	s.mutex.Lock()
	val, has := s.data["_type"]
	s.mutex.Unlock()
	if !has {
		return s.anyType
	}
	return val.(string)
}

// 如果有修正，就进行修正，
func (s *Object) refGet(field string) (val interface{}, has bool) {
	if s.modifyUsed {
		var modify IModify
		var origin interface{}
		switch s.modifyMode {
		case 2:
			modify = s.modifyMapOrArray
			origin = s.modifyMapOrArrayItem
		case 1:
			modify = s.modifyField[field]
			origin = s.data[field]
		}
		if modify != nil {
			if modify.Valid(s.modifyField, field) {
				modifyVal := modify.Value(s.modifyContext, field, origin)
				err := s.refSet(s.data, field, modifyVal)
				if err != nil {
					panic(err)
				}
			}
		}

	}
	val, has = s.data[field]
	return
}

func (s *Object) RefHas(field string) bool {
	s.mutex.RLock()
	_, has := s.refGet(field)
	s.mutex.RUnlock()
	return has
}

func (s *Object) RefGetUint(field string) uint {
	return uint(s.RefGetInt(field))
}

func (s *Object) RefGetInt(field string) int {
	s.mutex.Lock()
	val, has := s.refGet(field)
	s.mutex.Unlock()
	if has == false {
		return 0
	}

	return val.(int)
}

func (s *Object) RefGetBool(field string) bool {
	s.mutex.Lock()
	val, has := s.refGet(field)
	s.mutex.Unlock()
	if has == false {
		return false
	}

	return val.(bool)
}

func (s *Object) RefGetFloat64(field string) float64 {
	s.mutex.Lock()
	val := s.refFloat64(field)
	s.mutex.Unlock()
	return val
}

func (s *Object) refFloat64(field string) float64 {
	val, has := s.refGet(field)
	if has == false {
		return 0.0
	}
	return val.(float64)
}

func (s *Object) RefGetString(field string) string {
	s.mutex.Lock()
	val, has := s.refGet(field)
	s.mutex.Unlock()
	if has == false {
		return ""
	}
	return val.(string)
}

// 当前对象是否Object
// any类型无法判断
func (s *Object) RefIsObject(field string) (r bool) {
	switch styp := s.schemaType.(type) {
	case *schemax.MapType:
		switch styp.Value.(type) {
		case *schemax.AnyType:
		case *schemax.ClassType:
			return true
		default:
		}
	case *schemax.ArrayType:
		switch styp.Elem.(type) {
		case *schemax.AnyType:
		case *schemax.ClassType:
			return true
		default:
		}
	case *schemax.ClassType:
		declField := s.schemaDecl.GetField(field)

		switch declField.Type.(type) {
		case *schemax.AnyType:
		case *schemax.ClassType:
			return true
		case *schemax.MapType:
			return true
		case *schemax.ArrayType:
			return true
		default:
		}
	}

	return false
}

// 如果当前对象为nil，触发panic
func (s *Object) RefGetObject(field string) (r IObject) {
	if s.data == nil {
		panic("get field object failed: object is nil")
	}

	s.mutex.Lock()
	val, has := s.refGet(field)
	s.mutex.Unlock()

	if !has {
		if s.schemaDecl != nil || s.schemaType != nil { // 没有schema的时候，refset无法识别是否class
			s.mutex.Lock()
			err := s.refSet(s.data, field, nil)
			s.mutex.Unlock()
			if err != nil {
				panic(err)
			}
			val, _ = s.data[field]
		}

		if val == nil {
			val = NewObject(nil)
			s.mutex.Lock()
			s.data[field] = val
			s.mutex.Unlock()
		}
	}
	return val.(IObject)
}

func (s *Object) GetObjectByPath(path string) IObject {
	if string(path[0]) == "/" {
		path = path[1:]
	}
	pathArr := strings.Split(path, "/")
	return s.getObjectByPath(pathArr)
}

func (s *Object) getObjectByPath(pathArr []string) IObject {
	var cur IObject = s
	for {
		if len(pathArr) == 0 {
			break
		}
		field := pathArr[0]
		pathArr = pathArr[1:]
		cur = cur.RefGetObject(field)
		if cur == nil {
			return nil
		}
	}

	return cur
}

func (s *Object) RefGetArray(field string) IObject {
	return s.RefGetObject(field)
}
